package drds.plus.sql_process.abstract_syntax_tree.expression.item.function.extra_function;

import com.google.common.collect.Maps;
import drds.plus.sql_process.optimizer.OptimizerException;
import drds.tools.$;
import drds.tools.ClassSearcher;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
public class ExtraFunctionManager {
    private static Map<String, Class<?>> functionNameToFunctionMap = Maps.newConcurrentMap();
    private static String dummay_function = "dummy";
    private static String dummay_test_function = "dummytest";
    private static IExtraFunction dummyFunction; // 缓存一下dummy，避免每次都反射创建

    static {
        initFunctionList();
        dummyFunction = getExtraFunction(dummay_function);
        if (dummyFunction == null) {
            dummyFunction = getExtraFunction(dummay_test_function);
        }
    }


    private static void initFunctionList() {
        List<Class> classList = ClassSearcher.findSubClass(IExtraFunction.class, $.rootPackageName);
        List<Class> newClassList = classList.stream().filter(item -> item.getName().contains("function")).collect(Collectors.toList());
        for (Class clazz : newClassList) {
            addFuncion(clazz);
        }
    }

    public static void addFuncion(Class clazz) {
        try {
            IExtraFunction extraFunction = (IExtraFunction) clazz.newInstance();
            String[] functionNames = extraFunction.getFunctionNames();
            for (String functionName : functionNames) {
                Class oldClazz = functionNameToFunctionMap.put(functionName.toLowerCase(), clazz);
                if (oldClazz != null) {
                    log.warn(" dup function :" + functionName + ", old class : " + oldClazz.getName());
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 查找对应名字的函数类，忽略大小写
     */
    public static IExtraFunction getExtraFunction(String functionName) {
        Class clazz = functionNameToFunctionMap.get(functionName);
        IExtraFunction extraFunction = null;
        if (clazz == null) {
            return dummyFunction;
        }
        if (clazz != null) {
            try {
                extraFunction = (IExtraFunction) clazz.newInstance();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        if (extraFunction == null) {
            throw new OptimizerException("not found FunctionImpl : " + functionName);
        }
        return extraFunction;
    }

}
